﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Security.Permissions;
using System.Windows.Media;
using Bixas.Tangibilis.Input;
using System.Security;
using Bixas.Tangibilis.Utility;
using System.Diagnostics;


namespace Bixas.Tangibilis.Input
{
    /// <summary>
    /// this class manage input processing
    ///</summary>
    public class TouchDevice : InputDevice
    {

        private TouchSource _source;
        public static RoutedEvent PreviewInputReportEvent;
        public static RoutedEvent InputReportEvent;

        public TouchDevice(TouchSource Source)
        {
            InputManager.Current.HitTestInvalidatedAsync += new EventHandler(Current_HitTestInvalidatedAsync);
            _source = Source;
        }
        
        static TouchDevice()
        {
            PreviewInputReportEvent = GlobalEventManagerWrapper.RegisterRoutedEvent("PreviewInputReport", RoutingStrategy.Tunnel, typeof(InputReportEventHandler), typeof(TouchDevice));
            InputReportEvent = GlobalEventManagerWrapper.RegisterRoutedEvent("InputReport", RoutingStrategy.Bubble, typeof(InputReportEventHandler), typeof(TouchDevice));

        }
        void Current_HitTestInvalidatedAsync(object sender, EventArgs e)
        {
            foreach (KeyValuePair<int, TouchCursor> curs in _source._aliveCursorList)
            {
                curs.Value.Synchronize();
            }
        }

        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public void PreProcessInput(object sender, PreProcessInputEventArgs e)
        {
            RawTouchCursorInputEventArgs args = e.StagingItem.Input as RawTouchCursorInputEventArgs;

            // On ne filtre que les messages de type TouchCursorEventArgs
            if (args != null)
            {

                // Si la fenêtre principal n'est pas active
                // on désactive l'interception des messages
                if (args.CurrentWindow == null)
                {
                    args.Handled = true;
                }

                if (!args.Handled)
                {
                    if (args.Operation != RawTouchCursorOperation.Delete)
                    {
                        IInputElement enabledHit = args.Cursor.CursorOver;
                        IInputElement originalHit = (args.Cursor.RawCursorOver != null) ? ((IInputElement)args.Cursor.RawCursorOver.Target) : null;

                        enabledHit = (IInputElement)HitTest(args);
                        if (args.Cursor.CaptureMode == CaptureMode.Element)
                        {
                            if (enabledHit != args.Cursor.Captured)
                                enabledHit = args.Cursor.Captured;

                        }

                        if (args.Cursor.Captured != enabledHit)
                        {
                            UpdateCapture((DependencyObject)enabledHit, e);
                        }
                    }
                    else
                    {
                        UpdateCapture(null, e);
                    }
                }

            }

            /*if (!(e.StagingItem.Input is TouchCursorEventArgs) || e.StagingItem.Input.Handled)
            {
                if (e.StagingItem.Input is TouchCursorEventArgs)
                {
                    TouchCursorEventArgs input = (TouchCursorEventArgs)e.StagingItem.Input;
                    if ((input.RoutedEvent != null) && input.IsPreviewEvent)
                    {
                        input.IsReady = true;
                    }
                }
            }
            else
            {
                TouchCursorEventArgs args = (TouchCursorEventArgs)e.StagingItem.Input;
                 if (args.IsReady)
                {
                    if (!args.CurrentWindow.IsActive)
                    {
                        e.StagingItem.Input.Handled = true;
                    }
                }
                else
                {
                    if ((args.CurrentWindow == null))
                    {
                        if (args.RoutedEvent != null)
                        {
                            e.StagingItem.Input.Handled = true;
                        }
                    }
                    else
                    {
                        bool flag = false;
                        DependencyObject depObj = null;
                        if (args.RoutedEvent == null)
                        {
                            depObj = HitTest(args);
                            UpdateCapture(depObj, e);
                            flag = true;
                        }
                        else
                        {
                            depObj = (DependencyObject)args.Cursor.Captured;
                        }
                        if (depObj != null)
                        {
                            if (flag)
                            {
                                RaisePreviewCursorEvents(depObj, e);
                            }
                            else
                            {
                                RaiseCursorEvents(depObj, e);
                            }
                        }
                    }
                }
            }*/
        }

        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public void PostProcessInput(object sender, ProcessInputEventArgs e)
        {

            RawTouchCursorInputEventArgs args = e.StagingItem.Input as RawTouchCursorInputEventArgs;
            // On ne filtre que les messages de type TouchCursorEventArgs
            if (args != null)
            {
                bool flag = false;

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewDownEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorDownEvent;
                    flag = true;
                }

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewUpEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorUpEvent;
                    flag = true;
                }

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewMoveEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorMoveEvent;
                    flag = true;
                    Debug.WriteLine(args.Timestamp.ToString());
                }
                if (flag)
                {
                    if (args.Source == null) args.Source = args.Cursor.Captured;
                    args.IsReady = true;
                    e.PushInput(args, e.StagingItem);
                }
                if (!args.IsPreviewEvent)
                {
                    if (args.Operation == RawTouchCursorOperation.Add)
                    {
                        double left = args.Cursor.Left;
                        double top = args.Cursor.Top;
                        args.Cursor.SetPosition((int)left, (int)top);
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewDownEvent;
                    }
                    else if (args.Operation == RawTouchCursorOperation.Delete)
                    {
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewUpEvent;
                    }
                    else if (args.Operation == RawTouchCursorOperation.Update)
                    {
                        double left = args.Cursor.Left;
                        double top = args.Cursor.Top;
                        //args.Cursor.SetPosition((int)left, (int)top);
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewMoveEvent;
                    }
                    if (args.RoutedEvent != null)
                    {
                        if (args.Source == null) args.Source = args.Cursor.Captured;
                        args.IsPreviewEvent = true;
                        e.PushInput(args, e.StagingItem);
                    }
                }
            }


            /*  TouchCursorEventArgs input = (TouchCursorEventArgs)e.StagingItem.Input;
              if (input.Operation == CursorInputOperation.Add)
              {
                  input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewDownEvent;
              }
              else if (input.Operation == CursorInputOperation.Delete)
              {
                  input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewUpEvent;
              }
              else if (input.Operation == CursorInputOperation.Update)
              {
                  input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewMoveEvent;
              }
              if (input.RoutedEvent != null)
              {
                  input.Source = depObj;
                  input.IsPreviewEvent = true;
                  e.PushInput(input, e.StagingItem);
              }
              */
        }
        [SecurityCritical]
        public static Point GetPosition(Point OriginPosition, IInputElement relativeTo)
        {
            bool flag;
            PresentationSource presentationSource = null;
            if (relativeTo != null)
            {
                DependencyObject o = relativeTo as DependencyObject;
                DependencyObject containingVisual = InputElementWrapper.GetContainingVisual(o);
                if (containingVisual != null)
                {
                    presentationSource = Phydeaux.Utilities.Dynamic<PresentationSource>.Static.Function<PresentationSource>.Explicit<DependencyObject>.CreateDelegate("CriticalFromVisual", new Type[] { typeof(DependencyObject) }).Invoke(containingVisual);
                }
            }
            if ((presentationSource == null) || (presentationSource.RootVisual == null))
            {
                return new Point(0.0, 0.0);
            }

           // Point pt1 = PointUtilWrapper.ScreenToClient(OriginPosition, presentationSource);
            Point pt = PointUtilWrapper.TryClientToRoot(OriginPosition, presentationSource, false, out flag);
            if (!flag)
            {
                return new Point(0.0, 0.0);
            }
            Point pt2 = Bixas.Tangibilis.Input.InputElementWrapper.TranslatePoint(pt, presentationSource.RootVisual, (DependencyObject)relativeTo);
            return pt2;

        }

        private static DependencyObject HitTest(RawTouchCursorInputEventArgs args)
        {
            DependencyObject reference = null;
            if ((PresentationSource.FromVisual(args.CurrentWindow) != null))
            {
                Visual rootVisual = PresentationSource.FromVisual(args.CurrentWindow).RootVisual;
                //double left = ((MultiPointMouseDevice)args.DeviceInfo.DeviceVisual).Left;
                //double top = ((MultiPointMouseDevice)args.DeviceInfo.DeviceVisual).Top;

                double left = args.Cursor.Left;
                double top = args.Cursor.Top;
                Point point = new Point(left, top);
                HitTestResult result = VisualTreeHelper.HitTest(rootVisual, point);
                if (result != null)
                {
                    reference = result.VisualHit;
                }
                while (reference != null)
                {
                    reference = VisualTreeHelper.GetParent(reference);
                    if (reference is ITouchCursorEvent)
                    {
                        return reference;
                    }
                }
            }
            return reference;
        }

        private static void UpdateCapture(DependencyObject depObj, PreProcessInputEventArgs e)
        {
            RawTouchCursorInputEventArgs input = (RawTouchCursorInputEventArgs)e.StagingItem.Input;
            if ((depObj == null) && (input.Cursor.Captured != null))
            {
                input.RoutedEvent = TouchCursorEvents.TouchCursorLeaveEvent;
                input.Source = input.Cursor.Captured;
                input.Cursor.Captured = null;
                InputManager.Current.ProcessInput(input);
                e.StagingItem.Input.Handled = true;
            }
            if (depObj != null)
            {
                if ((input.Cursor.Captured != null) && (input.Cursor.Captured != depObj))
                {
                    input.RoutedEvent = TouchCursorEvents.TouchCursorLeaveEvent;
                    input.Source = input.Cursor.Captured;
                    //input.Cursor.Captured.RaiseEvent(input);
                    input.Cursor.Captured = null;
                    InputManager.Current.ProcessInput(input);
                }
                if (input.Cursor.Captured == null)
                {
                    input.Cursor.Captured = (IInputElement)depObj;
                    input.RoutedEvent = TouchCursorEvents.TouchCursorEnterEvent;
                    //input.Source = depObj;
                    //element3.RaiseEvent(input);
                    input.Source = input.Cursor.Captured;
                    InputManager.Current.ProcessInput(input);

                }
            }
        }

        public override PresentationSource ActiveSource
        {
            get { throw new NotImplementedException(); }
        }

        public override IInputElement Target
        {
            get { throw new NotImplementedException(); }
        }



    }

    internal delegate void InputReportEventHandler(object sender, EventArgs e);
    
 

}
